package linz


open class TestConstructor(v:Int){
    constructor(v:Int, s:String):this(v){

    }
}

open class  Person {
    var info = "information"
    get() = field.capitalize()
    set(value) {
        field = "**[$value]**"
    }


    var name = "john"
    get(){
        return "you have a $field"
    }
    set(value) {
        field = "**[$value]**"
    }

    //计算属性
    val age :Int
    get() = (1..1000).shuffled().first() //1-1000随机值

    /**
     * 防范竞争态条件
     */
    private var department :String ? = ""
    // 当field 可能null，可能空，就必须采用防范竞争态条件
    fun getDepartmentInfo():String{
        return department?.let {
            if (it.isBlank()) {
                "值为空请重新赋值"
            }else{
                "resunt:$it"
            }
        } ?: "这个是null请赋值"

    }
}


class Student(var name: String, val sex: Char, val age: Int)


class Programmer : Person() {

    fun code(){
        println("coding...")
    }

    fun learning(){
        println("learning ...")
    }
}

// todo 执行顺序 first
class School(name:String){ // 主构造
    // todo second
    val mName = name  // 和init同步进行，看谁放在前面
    /**
     * 初始化块代码，类似于java{}, 主构造调用时调用
     */
    init {
        //todo  third
        println("主构造$mName ")

//        println("create year : $age")  //报错

        //对初始化参数进行验证
        // 如果参数不满足 require条件，抛出异常信息
        require(!name.isBlank()){"抛出异常！"}
    }

    var age = 180


    constructor(name: String = "雅礼中学",year:Int,local:String):this(name){ //次构造，次构造必须调用主构造
        // todo four
        println("次构造")
    }
}


fun main() {
    val person = Person()

    println(person.info)
    println(person.name)
    println(person.age)
    println(person.getDepartmentInfo())

    val stu = Student("Alice", '1', 18)
    println(stu.name)

    var school = School("北京四中");

    //todo 智能as
    var p: Person = Programmer()
    // 第一次转换后，下面的自动转成Programmer
    (p as Programmer).code()

    p.learning()


    //todo 匿名对象
    val inner = object :KtClass(){
        override fun add(info: String) {
//            super.add(info
            println("匿名对象 add:$info")
        }
    }

    inner.add("information")


    //todo 实现Java接口 有两种方式，Kt只支持下面这种
    val p3 = object :Runnable{
        override fun run() {
            println("Runnable run ...")
        }
    }
    p3.run()

    // lambda 表达 Kt 不支持这种写法
    val p4 = Runnable { println("lambda Runnable run ...") }
    p4.run()

    //KT 接口实现
    val p5 = object :RunnableKt{
        override fun run() {
            println("RunnableKt ...")
        }
    }

    p5.run()

    // todo 内部类
    Body("Body").Heart().run()
    Body("Body").Hand().LeftHand().run()

    // todo 嵌套类
    Outer().show()

}


/**
 *  外部类可以访问内部类
 *  内部
 *  "互通"
 */
class Body(var bodyInfo:String) {

    fun run(){
        println("${Heart().run()}")
    }

    inner class Heart {
        fun run() = println("心脏访问身体信息$bodyInfo")
    }

    inner  class Hand{
        inner class LeftHand{
            fun run() = println("右手信息：$bodyInfo")
        }

        inner class RightHand{
            fun run() = println("Right手信息：$bodyInfo")
        }
    }
}


/**
 * 嵌套类
 * 外通
 * 内不通
 */
class Outer{
    val info:String = "OK"

    fun show(){
        Nested().output()
    }

    class Nested{
        fun output() = println("输出")
    }
}


open class KtClass{
    open fun add(info:String) = println("KtClass add:$info")
    open fun del(info:String) = println("KtClass del:$info")
}

interface RunnableKt{
    fun run(){
    }
}

//todo 多个实现，调用那个
open class Rectangle {
    open fun draw() { /* ... */ }
}

interface Polygon {
    fun draw() { /* ... */ } // interface members are 'open' by default
}

class Square() : Rectangle(), Polygon {
    // The compiler requires draw() to be overridden:
    override fun draw() {
        super<Rectangle>.draw() // call to Rectangle.draw()
        super<Polygon>.draw() // call to Polygon.draw()
    }
}
